package Serveur;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import java.util.Iterator;

import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

import security.module.SimpleMonServeurLoginModule;

public class Serveur extends UnicastRemoteObject implements InterfacePublic, InterfacePrivee{
	private static final long serialVersionUID = 1L;
	private ArrayList<Utilisateur> listeUtilisateurs;
	private ArrayList<Twouit> listeTwouits;
	private ArrayList<String> listeTopics;
	private HashMap<InterfaceClient, ArrayList<InterfaceClient>> listeFauxlovers;
	
	public Serveur(int port, RMISSLClientSocketFactory clientFactory, RMISSLServerSocketFactory serverFactory) throws RemoteException{
		super(port, clientFactory, serverFactory);
		this.listeUtilisateurs = new ArrayList<Utilisateur>();
		this.listeTwouits = new ArrayList<Twouit>();
		this.listeTopics = new ArrayList<String>();
		this.listeFauxlovers = new HashMap<InterfaceClient, ArrayList<InterfaceClient>>();
	}
	
	public static void main(String[] args){
		System.out.println("Creation de l'objet  serveur");
		// il faut un security manager car on doit utiliser un fichier de policy pour pouvoir utiliser JAAS
		if (System.getSecurityManager() == null) { 
			System.setSecurityManager(new java.rmi.RMISecurityManager()); 	
		}
		
		RMISSLClientSocketFactory clientFactory = new RMISSLClientSocketFactory();
		RMISSLServerSocketFactory serverFactory = new RMISSLServerSocketFactory();
		
		InterfacePublic objserveur = null;
		try {
			objserveur = new Serveur(0, clientFactory, serverFactory);
		} catch (RemoteException e1) {
			e1.printStackTrace();
		}
		
		try{
			Naming.rebind("rmi://localhost:"+ 2004 +"/Serveur", (Remote) objserveur);
			System.out.println("Serveur lancé sur le port " + 2004);
			
		} catch (RemoteException e) {
			e.printStackTrace();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("Attente d invocation, Ctrl-C pour stopper!");
	}
	
	@Override
	public InterfacePrivee logon(InterfaceClient c, String uname, String passwd) throws RemoteException, LoginException {
		InterfacePrivee iprivco = null;
		if( c.getUtilisateur().isConnect() ){
			System.out.println("Client déjà connecté");
		}
		else{
			// Verifier si l'utilisateur a bien donné un login et passwd egaux à testUser et testPassword
			// Si non, renvoyer une instance de LoginException 

			LoginContext lc = new LoginContext("MonServeur", new security.module.RemoteCallbackHandler(uname, passwd));
			SimpleMonServeurLoginModule.listeUtilisateurs = listeUtilisateurs;
			try{
				lc.login();
				System.out.println("Authentifié le sujet "+ lc.getSubject());
				iprivco = this;
				c.getUtilisateur().setIsConnect(true);
				System.out.println("Connexion de " + uname);
			}
			catch (LoginException e){
				System.out.println("Recu "+ uname + " et " + passwd + " mais, après vérif, ils sont incorrects");
				throw e;
			}
		}
		return iprivco;
	}
	
	//Lance le processus d'inscription
	@Override
	public void inscription(Utilisateur u) throws RemoteException {
		listeUtilisateurs.add(u);
		System.out.println("Inscription de l'utilisateur : " + u);		
	}
	//Ajoute l'utilisateur courant à la liste des fauxlover(Chaque utilisateur peut etre suivi)
	@Override
	public void addToListeFauxlover(InterfaceClient newUser) throws RemoteException {
		this.listeFauxlovers.put(newUser, new ArrayList<InterfaceClient>());
	}
	//Lance le processus pour twouitter
	@Override
	public void twouitter(Twouit twouit, InterfaceClient c) throws RemoteException {
		listeTwouits.add(twouit);
		addTopic(twouit.getTopic());
		
		System.out.println("Twouit " + twouit + " ajouté par " + twouit.getUtilisateur().getLogin());
		for(int i = 0; i < listeFauxlovers.get(c).size(); i++) {
			listeFauxlovers.get(c).get(i).setListeTwouit(twouit);
		}
	}
	
	private void addTopic(String topic){
		if( !listeTopics.contains(topic) )
			listeTopics.add(topic);
	}
	//Permet de retwouitter
	@Override
	public void retwouitter(InterfaceClient user, Twouit twouit) throws RemoteException {
		user.setListeTwouit(twouit);		
	}
	//Lance le processus pour faux lover quelqu'un
	@Override
	public void addFauxlover(InterfaceClient user, String loginUserToFauxlover) throws RemoteException {
		boolean loginExist = false;
		for(int i = 0; i < this.listeUtilisateurs.size(); i++) {
			Utilisateur tmp = this.listeUtilisateurs.get(i);
			if (tmp.getLogin().equals(loginUserToFauxlover)) {
				loginExist = true;
			}
		}
		if(loginExist) {
			Set<InterfaceClient> cle = this.listeFauxlovers.keySet();
			Iterator<InterfaceClient> it = cle.iterator();
			while(it.hasNext()) {
				InterfaceClient tmp = (InterfaceClient)it.next();
				if(tmp.getUtilisateur().getLogin().equals(loginUserToFauxlover)) {
					this.listeFauxlovers.get(tmp).add(user);
					break;
				}
				
			}
		}
	}
	//Renvoie la liste des dernier twouit d'un utilisateur
	@Override
	public ArrayList<Twouit> getDerniersTwouitUtilisateur(String utilisateur) throws RemoteException {
		ArrayList<Twouit> liste = new ArrayList<Twouit>();
		for (Twouit t : listeTwouits) {
			if( t.utilisateur.login.equals(utilisateur) )
				liste.add(t);
		}
		return liste;
	}
	//Renvoie la liste des dernier twouit en fonction d'un topic précis
	@Override
	public ArrayList<Twouit> getDerniersTwouitTopic(String topic) throws RemoteException {
		ArrayList<Twouit> liste = new ArrayList<Twouit>();
		for (Twouit t : listeTwouits) {
			if( t.topic.equals(topic) )
				liste.add(t);
		}
		return liste;
	}
	//Renvoie la liste des topics
	@Override
	public ArrayList<String> getListeTopics() throws RemoteException {
		return listeTopics;
	}
	//Renvoie la liste des utilisateurs connectés
	@Override
	public ArrayList<Utilisateur> getListeUtilisateurs() throws RemoteException {
		return listeUtilisateurs;
	}
	//Renvoie la liste des faux lovers d'un utilisateur precis
	@Override
	public ArrayList<InterfaceClient> getFauxlovers(InterfaceClient c) throws RemoteException {
		return this.listeFauxlovers.get(c);
	}
	//Lance le processus pour se deconnecter
	@Override
	public void seDeconnecter(InterfaceClient c) throws RemoteException {
		c.getUtilisateur().setIsConnect(false);
		System.out.println("Deconnexion de " + c.getUtilisateur().getLogin());
	}

}
